package com.zlp.netty.nio;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static com.zlp.netty.buffer.ByteBufferUtil.debugAll;
import static com.zlp.netty.buffer.ByteBufferUtil.debugRead;

/**
 * @author: zhulaiping
 * @time: 2022/8/18 17:13
 */
@Slf4j
public class NIOServerDemo3_Selector {

    public static void main(String[] args) throws IOException {
        //1.创建selector
        Selector selector = Selector.open();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8080));
        serverSocketChannel.configureBlocking(false);
        //2.建立selecto与channel的联系（注册）

        SelectionKey sscKey = serverSocketChannel.register(selector, 0, null);
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        while (true){
            //3. select方法，没有事件发生线程阻塞i，有事件线程才会恢复运行,有事件要处理或取消，否则会一直循环
            selector.select();
            //4.处理事件，selectKeys内部包含了所有发生的事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                log.debug("key:{}",key);
               if(key.isAcceptable()){
                   ServerSocketChannel channel = (ServerSocketChannel)key.channel();
                   SocketChannel socketChannel = channel.accept();
                   socketChannel.configureBlocking(false);
                   ByteBuffer buffer = ByteBuffer.allocate(8);
                   SelectionKey scKey = socketChannel.register(selector, 0, buffer);
                   scKey.interestOps(SelectionKey.OP_READ);
                   log.debug("{}",socketChannel);
               }else if(key.isReadable()){
                   try {
                       SocketChannel channel = (SocketChannel)key.channel();
                       ByteBuffer buffer = (ByteBuffer)key.attachment();
                       int read = channel.read(buffer);
                       if(read == -1){
                           //正常结束，也需要取消key,
                           key.cancel();
                       }else{
                           //buffer.flip();
                           //debugAll(buffer);
                           //System.out.println(Charset.defaultCharset().decode(buffer));
                           split(buffer);
                           if(buffer.limit() == buffer.position()){
                               ByteBuffer allocate = ByteBuffer.allocate(buffer.capacity() * 2);
                               buffer.flip();
                               allocate.put(buffer);
                               key.attach(allocate);
                           }
                       }
                   }catch (Exception e){
                       e.printStackTrace();
                       //当客户端异常退出时，不加try catch 会导致进程结束
                       //把注册到selector的channel移除，
                       key.cancel();
                   }
               }
               iterator.remove();
            }

        }
    }

    private static void split(ByteBuffer buffer) {
        buffer.flip();//切换为读模式
        for (int i=0;i<buffer.limit();i++){
            if (buffer.get(i) == '\n') {
                int len = i + 1 - buffer.position();
                ByteBuffer target = ByteBuffer.allocate(len);
                for (int j=0;j<len;j++){
                    target.put(buffer.get());
                }
                debugAll(target);
            }
        }
        buffer.compact();
    }
}
